﻿namespace H2.Streams.RawTypes
{
    using H2.DataTypes;
    using H2.Streams;
    using H2.Streams.Sections;
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;

    public class Bitmap : IComparable<H2.Streams.RawTypes.Bitmap>
    {
        internal int ChunkStartOffset;
        private MapStream Map;

        internal Bitmap(MapStream map, int chunkStartOffset)
        {
            this.Map = map;
            this.ChunkStartOffset = chunkStartOffset;
        }

        public int CompareTo(H2.Streams.RawTypes.Bitmap other)
        {
            return this.ChunkStartOffset.CompareTo(other.ChunkStartOffset);
        }

        public System.Drawing.Bitmap LoadPreview(ResourceStream MainMenu, ResourceStream Shared, ResourceStream SpShared)
        {
            return this.LoadPreview(MainMenu, Shared, SpShared, 0, 0);
        }

        public System.Drawing.Bitmap LoadPreview(ResourceStream MainMenu, ResourceStream Shared, ResourceStream SpShared, int SBSPIndex, int PaletteIndex)
        {
            ResourceStream stream;
            PixelFormat format;
            int num5;
            System.Drawing.Bitmap bitmap;
            int width = this.Width;
            int height = this.Height;
            int offset = this.LOD1Offset;
            long num4 = offset & ((long) 0xc0000000L);
            offset &= 0x3fffffff;
            switch (num4)
            {
                case 0x80000000L:
                    stream = Shared;
                    break;

                case 0xc0000000L:
                    stream = SpShared;
                    break;

                case 0L:
                    stream = new ResourceStream(this.Map.Stream);
                    break;

                case 0x40000000L:
                    stream = MainMenu;
                    break;

                default:
                    return null;
            }
            width--;
            width = (width >> 1) | width;
            width = (width >> 2) | width;
            width = (width >> 4) | width;
            width = (width >> 8) | width;
            width = (width >> 0x10) | width;
            width++;
            height--;
            height = (height >> 1) | height;
            height = (height >> 2) | height;
            height = (height >> 4) | height;
            height = (height >> 8) | height;
            height = (height >> 0x10) | height;
            height++;
            byte[] raw = stream.ReadBytesAt(offset, this.LOD1Size, false);
            if (raw.Length != 0)
            {
                int num6;
                byte[] buffer2;
                switch (this.Format)
                {
                    case FormatEnum.A8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, this.Depth, 8, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        buffer2 = new byte[raw.Length * 4];
                        for (int i = 0; i < raw.Length; i++)
                        {
                            int index = i * 4;
                            buffer2[index] = 0xff;
                            buffer2[index + 1] = 0xff;
                            buffer2[index + 2] = 0xff;
                            buffer2[index + 3] = raw[i];
                        }
                        raw = buffer2;
                        goto Label_06E9;

                    case FormatEnum.Y8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, this.Depth, 8, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        buffer2 = new byte[raw.Length * 4];
                        for (int j = 0; j < raw.Length; j++)
                        {
                            int num16 = j * 4;
                            buffer2[num16] = raw[j];
                            buffer2[num16 + 1] = raw[j];
                            buffer2[num16 + 2] = raw[j];
                            buffer2[num16 + 3] = 0xff;
                        }
                        raw = buffer2;
                        goto Label_06E9;

                    case FormatEnum.A8Y8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, this.Depth, 0x10, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        num6 = raw.Length / 2;
                        buffer2 = new byte[num6 * 4];
                        for (int k = 0; k < num6; k++)
                        {
                            int num12 = k * 2;
                            buffer2[num12] = raw[num12];
                            buffer2[num12 + 1] = raw[num12];
                            buffer2[num12 + 2] = raw[num12];
                            buffer2[num12 + 3] = raw[num12 + 1];
                        }
                        raw = buffer2;
                        goto Label_06E9;

                    case FormatEnum.R5G6B5:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, -1, 0x10, true);
                        }
                        num5 = 2;
                        format = PixelFormat.Format16bppRgb565;
                        goto Label_06E9;

                    case FormatEnum.A1R5G5B5:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, -1, 0x10, true);
                        }
                        num5 = 2;
                        format = PixelFormat.Format16bppArgb1555;
                        goto Label_06E9;

                    case FormatEnum.A4R4G4B4:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, -1, 0x10, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        buffer2 = new byte[raw.Length * 2];
                        for (int m = 0; m < raw.Length; m += 2)
                        {
                            int num8 = m * 2;
                            buffer2[num8] = (byte) (raw[m] & 240);
                            buffer2[num8 + 1] = (byte) (raw[m] & 15);
                            buffer2[num8 + 2] = (byte) (raw[m + 1] & 240);
                            buffer2[num8 + 3] = (byte) (raw[m + 1] & 15);
                        }
                        raw = buffer2;
                        goto Label_06E9;

                    case FormatEnum.X8R8G8B8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, width, height, -1, 0x20, true);
                        }
                        format = PixelFormat.Format32bppRgb;
                        num5 = 4;
                        goto Label_06E9;

                    case FormatEnum.A8R8G8B8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, width, height, this.Depth, 0x20, true);
                        }
                        format = PixelFormat.Format32bppArgb;
                        num5 = 4;
                        goto Label_06E9;

                    case FormatEnum.DXT1:
                        raw = Bitmaps.DecodeDXT1(width, height, raw);
                        format = PixelFormat.Format32bppArgb;
                        num5 = 4;
                        goto Label_06E9;

                    case FormatEnum.DXT2And3:
                        raw = Bitmaps.DecodeDXT23(width, height, raw);
                        format = PixelFormat.Format32bppArgb;
                        num5 = 4;
                        goto Label_06E9;

                    case FormatEnum.DXT4And5:
                        raw = Bitmaps.DecodeDXT45(width, height, raw);
                        format = PixelFormat.Format32bppArgb;
                        num5 = 4;
                        goto Label_06E9;

                    case FormatEnum.P8:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, this.Depth, 8, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        if (!Bitmaps.H2PaletteLoaded)
                        {
                            Bitmaps.LoadHalo2Palette();
                        }
                        buffer2 = new byte[raw.Length * 4];
                        for (int n = 0; n < raw.Length; n++)
                        {
                            int num14 = n * 4;
                            buffer2[num14] = Bitmaps.H2Palette[raw[n]].R;
                            buffer2[num14 + 1] = Bitmaps.H2Palette[raw[n]].G;
                            buffer2[num14 + 2] = Bitmaps.H2Palette[raw[n]].B;
                            buffer2[num14 + 3] = Bitmaps.H2Palette[raw[n]].A;
                        }
                        raw = buffer2;
                        goto Label_06E9;

                    case FormatEnum.Lightmap:
                    {
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, this.PixelOffset, width, height, this.Depth, 8, true);
                        }
                        num5 = 4;
                        format = PixelFormat.Format32bppArgb;
                        buffer2 = new byte[raw.Length * 4];
                        LightMap.Palette palette = this.Map.Sbsp[SBSPIndex, Tags.SearchType.Index].LightMap.Palettes[PaletteIndex];
                        for (int num17 = 0; num17 < raw.Length; num17++)
                        {
                            int num18 = num17 * 4;
                            buffer2[num18] = palette.Colors[raw[num17]].R;
                            buffer2[num18 + 1] = palette.Colors[raw[num17]].G;
                            buffer2[num18 + 2] = palette.Colors[raw[num17]].B;
                            buffer2[num18 + 3] = palette.Colors[raw[num17]].A;
                        }
                        raw = buffer2;
                        goto Label_06E9;
                    }
                    case FormatEnum.Unknown:
                        if (this.Swizzle)
                        {
                            raw = Bitmaps.Swizzle(raw, 0, width, height, -1, 0x10, true);
                        }
                        num5 = 2;
                        format = PixelFormat.Format32bppArgb;
                        num6 = raw.Length / 2;
                        buffer2 = new byte[num6 * 4];
                        for (int num9 = 0; num9 < num6; num9++)
                        {
                            int num10 = num9 * 2;
                            buffer2[num10 * 2] = raw[num10 + 1];
                            buffer2[(num10 * 2) + 1] = raw[num10 + 1];
                            buffer2[(num10 * 2) + 2] = raw[num10 + 1];
                            buffer2[(num10 * 2) + 3] = raw[num10];
                        }
                        raw = buffer2;
                        goto Label_06E9;
                }
            }
            return new System.Drawing.Bitmap(1, 1);
        Label_06E9:
            bitmap = new System.Drawing.Bitmap(width, height);
            BitmapData bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, format);
            Marshal.Copy(raw, 0, bitmapdata.Scan0, (width * height) * num5);
            bitmap.UnlockBits(bitmapdata);
            return bitmap;
        }

        public short Depth
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 8, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 8, value, true);
            }
        }

        public Bitmask Flags
        {
            get
            {
                Bitmask bitmask = new Bitmask(new string[] { "^2 Dimensions", "Compressed", "Palettized", "Swizzled", "Linear", "v16u16", "MIP Map Debug Level", "Prefer Stutter (Prefer Low Detail)", "Interlaced?" }, 2);
                bitmask.SetAllData(this.Map.ReadBytesAt(this.ChunkStartOffset + 14, 2, true));
                return bitmask;
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset, value, true);
            }
        }

        public FormatEnum Format
        {
            get
            {
                return (FormatEnum) this.Map.ReadInt16At(this.ChunkStartOffset + 12, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 12, (int) value, true);
            }
        }

        public short Height
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 6, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 6, value, true);
            }
        }

        public int LOD1Offset
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 0x1c, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x1c, value, true);
            }
        }

        public int LOD1Size
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 0x34, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x34, value, true);
            }
        }

        public int LOD2Offset
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 0x20, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x20, value, true);
            }
        }

        public int LOD2Size
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 0x38, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x38, value, true);
            }
        }

        public int LOD3Offset
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 0x24, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x24, value, true);
            }
        }

        public int LOD3Size
        {
            get
            {
                return this.Map.ReadInt32At(this.ChunkStartOffset + 60, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 60, value, true);
            }
        }

        public short MipMapCount
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 0x12, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x12, value, true);
            }
        }

        public short PixelOffset
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 20, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 20, value, true);
            }
        }

        public RawLocations RawLocation
        {
            get
            {
                switch ((this.LOD1Offset & ((long) 0xc0000000L)))
                {
                    case 0L:
                        return RawLocations.Internal;

                    case 0x40000000L:
                        return RawLocations.MainMenu;

                    case 0x80000000L:
                        return RawLocations.Shared;

                    case 0xc0000000L:
                        return RawLocations.SinglePlayerShared;
                }
                return RawLocations.Unknown;
            }
        }

        public short RegPointX
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 14, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 14, value, true);
            }
        }

        public short RegPointY
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 0x10, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 0x10, value, true);
            }
        }

        public bool Swizzle
        {
            get
            {
                return this.Flags.Bits[3];
            }
        }

        public short Type
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 10, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 10, value, true);
            }
        }

        public short Width
        {
            get
            {
                return this.Map.ReadInt16At(this.ChunkStartOffset + 4, true);
            }
            set
            {
                this.Map.WriteAt(this.ChunkStartOffset + 4, value, true);
            }
        }

        public enum FormatEnum
        {
            A1R5G5B5 = 8,
            A4R4G4B4 = 9,
            A8 = 0,
            A8R8G8B8 = 11,
            A8Y8 = 3,
            AY8 = 2,
            DXT1 = 14,
            DXT2And3 = 15,
            DXT4And5 = 0x10,
            Lightmap = 0x12,
            P8 = 0x11,
            R5G6B5 = 6,
            Unknown = 0x16,
            X8R8G8B8 = 10,
            Y8 = 1
        }
    }
}

